package com.quectel.core.module.forum.service.impl.mongo;

import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.constant.core.forum.ForumConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.constants.MongoCollectionConstants;
import com.quectel.core.module.MongoAuthComponent;
import com.quectel.core.module.forum.dto.mongo.ForumCommentDto;
import com.quectel.core.module.forum.dto.mongo.ForumMsgDto;
import com.quectel.core.module.forum.dto.mongo.ForumPostDto;
import com.quectel.core.module.forum.entity.mongo.ForumMsgModel;
import com.quectel.core.module.forum.service.mongo.ForumCommentService;
import com.quectel.core.module.forum.service.mongo.ForumMsgService;
import com.quectel.core.module.forum.service.mongo.ForumPersonCountService;
import com.quectel.core.module.forum.service.mongo.ForumPostService;
import com.quectel.core.module.mobileuser.dto.MobileUserDto;
import com.quectel.core.module.mobileuser.service.MobileUserService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.Request;
import com.quectel.util.kit.Snowflake;
import com.quectel.util.mongo.MongodbUtils;
import com.quectel.util.spring.SpringUtils;
import com.quectel.util.thread.ThreadPoolUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author zhangheng
 * @email nolan.zhang@quectel.com
 * @date 2023/5/8 15:52
 * @description 帖子
 */
@DubboService
@Slf4j
public class ForumMsgServiceImpl implements ForumMsgService {

    private static final ThreadPoolExecutor executorService = ThreadPoolUtils.createCommonIOBoundPool("forum_asynchronous_pool");


    @Autowired
    private MongoAuthComponent mongoAuthComponent;

    @Autowired
    private MobileUserService mobileUserService;
    @Autowired
    private ForumPostService forumPostService;
    @Autowired
    private ForumCommentService forumCommentService;
    @Autowired
    private ForumPersonCountService forumPersonCountService;


    private Criteria sqlWhere(Map<String, Object> params) {
        Request request = Request.configParams(params);

        Criteria criteria = new Criteria();

        Long mobileUserId = request.getLong(LambdaUtil.getFieldName(ForumMsgModel::getMobileUserId));
        if (mobileUserId != null) {
            criteria.and(LambdaUtil.getFieldName(ForumMsgModel::getMobileUserId)).is(mobileUserId);
        }

        Long operatorId = request.getLong(LambdaUtil.getFieldName(ForumMsgModel::getOperatorId));
        if (operatorId != null) {
            criteria.and(LambdaUtil.getFieldName(ForumMsgModel::getOperatorId)).is(operatorId);
        }

        Long operatedPersonId = request.getLong(LambdaUtil.getFieldName(ForumMsgModel::getOperatedPersonId));
        if (operatedPersonId != null) {
            criteria.and(LambdaUtil.getFieldName(ForumMsgModel::getOperatedPersonId)).is(operatedPersonId);
        }

        Long businessId = request.getLong(LambdaUtil.getFieldName(ForumMsgModel::getBusinessId));
        if (businessId != null) {
            criteria.and(LambdaUtil.getFieldName(ForumMsgModel::getBusinessId)).is(businessId);
        }

        Object[] msgTypes = request.getArray(ForumConstants.MSG_TYPES, Object.class);
        if (msgTypes != null && msgTypes.length > 0) {
            criteria.and(LambdaUtil.getFieldName(ForumMsgModel::getForumMsgType)).in(msgTypes);
        }

        Byte readStatus = request.getByte(LambdaUtil.getFieldName(ForumMsgModel::getReadStatus));
        if (readStatus != null) {
            criteria.and(LambdaUtil.getFieldName(ForumMsgModel::getReadStatus)).is(readStatus);
        }

        return new Criteria().andOperator(criteria);
    }

    @Override
    public void operateSuccessNotify(Long tenantId, Long businessId, Long operatorId, Long operatedPersonId, Byte handleType) {

        //发送消息 可以异步提交
        CompletableFuture.runAsync(() -> {
            ForumMsgService forumMsgService = SpringUtils.getBean(ForumMsgService.class);
            forumMsgService.sendMsg(businessId, operatorId, operatedPersonId, handleType);
        }, executorService).whenComplete((r, e) -> {
            if (e != null) {
                log.error("发送消息异步执行异常信息: " + e.getMessage(), e);
            }
        });

        //记录人员数量 可以异步提交
        CompletableFuture.runAsync(() -> {
            forumPersonCountService.updateCommentCount(tenantId, operatorId, handleType, 1);
        }, executorService).whenComplete((r, e) -> {
            if (e != null) {
                log.error("记录人员数量异步执行异常信息: " + e.getMessage(), e);
            }
        });
    }

    @Override
    public void deleteOneByParams(Map<String, Object> params) {
        ForumMsgModel forumMsgModel = MongodbUtils.queryOne(
                new Query(
                        sqlWhere(params)
                ),
                ForumMsgModel.class
                ,
                MongoCollectionConstants.FORUM_MSG
        );
        if (forumMsgModel != null) {
            MongodbUtils.delete(forumMsgModel, MongoCollectionConstants.FORUM_MSG);
        }
    }


    @Override
    public void batchUpdateReadStatus(Map<String, Object> params) {
        MongodbUtils.update(
                new Query(
                        sqlWhere(params)
                ),
                new Update()
                        .set(LambdaUtil.getFieldName(ForumMsgModel::getReadStatus), SystemConstants.YES)
                ,
                MongoCollectionConstants.FORUM_MSG
        );
    }

    @Override
    public void sendMsg(Long businessId, Long operatorId, Long operatedPersonId, Byte type) {
        if (businessId == null || operatorId == null || operatedPersonId == null || type == null) {
            return;
        }

        ForumConstants.ForumHandleType byType = ForumConstants.ForumHandleType.getByType(type);
        if (byType == null) {
            return;
        }

        Date now = new Date();
        //先记录自己的操作
        ForumMsgDto myMsg = new ForumMsgDto();
        myMsg.setMobileUserId(operatorId);
        myMsg.setOperatorId(operatorId);
        myMsg.setOperatedPersonId(operatedPersonId);
        myMsg.setForumMsgType(type);
        myMsg.setBusinessId(businessId);
        myMsg.setCreateTime(now);
        myMsg.setReadStatus(SystemConstants.YES);
        save(myMsg);
        //假如通知人和操作人不是一个,还需要通知一下对方标记为未读
        if (!operatorId.equals(operatedPersonId)) {
            ForumMsgDto otherMsg = new ForumMsgDto();
            otherMsg.setMobileUserId(operatedPersonId);
            otherMsg.setOperatorId(operatorId);
            otherMsg.setOperatedPersonId(operatedPersonId);
            otherMsg.setForumMsgType(type);
            otherMsg.setBusinessId(businessId);
            otherMsg.setCreateTime(now);
            otherMsg.setReadStatus(SystemConstants.NO);
            save(otherMsg);
        }
    }

    @Override
    public ForumMsgDto selectById(Long id) {
        ForumMsgModel one = MongodbUtils.findOne(id, MongoCollectionConstants.FORUM_MSG, ForumMsgModel.class);
        return CopyUtils.copyObj(one, ForumMsgDto.class);
    }

    @Override
    public List<ForumMsgDto> queryList(Map<String, Object> params) {
        Request request = Request.configParams(params);
        return
                MongodbUtils.page(
                        new Query(sqlWhere(params)),
                        request.getPageNo() - 1,
                        request.getPageSize(),
                        Sort.by(Sort.Direction.DESC, SystemConstants.MONGO_ENTITY_ID_FLAG),
                        ForumMsgModel.class,
                        MongoCollectionConstants.FORUM_MSG
                ).stream().map(model -> {
                    ForumMsgDto dto = CopyUtils.copyObj(model, ForumMsgDto.class);
                    //查询操作人头像
                    MobileUserDto operator = mobileUserService.selectCacheById(dto.getOperatorId());
                    if (operator != null) {
                        //查询对应的实体
                        dto.setOperatorNickname(operator.getNickname());
                        dto.setOperatorHeadImg(operator.getHeadImg());
                    }

                    MobileUserDto operatedPerson = mobileUserService.selectCacheById(dto.getOperatedPersonId());
                    if (operatedPerson != null) {
                        //查询对应的实体
                        dto.setOperatedNickname(operatedPerson.getNickname());
                        dto.setOperatedHeadImg(operatedPerson.getHeadImg());
                    }

                    if (dto.getBusinessId() != null) {
                        if (dto.getForumMsgType().equals(ForumConstants.ForumHandleType.POST.getType())

                                || dto.getForumMsgType().equals(ForumConstants.ForumHandleType.LIKE.getType())
                                || dto.getForumMsgType().equals(ForumConstants.ForumHandleType.SHARE.getType())
                        ) {
                            Map<String, Object> forumParams = new HashMap<>();
                            forumParams.put(LambdaUtil.getFieldName(ForumPostDto::getId), dto.getBusinessId());
                            forumParams.put(LambdaUtil.getFieldName(ForumPostDto::getDeletedFlag), SystemConstants.NO);
                            List<ForumPostDto> forumPostDtos = forumPostService.queryList(forumParams);
                            if (CollectionUtils.isNotEmpty(forumPostDtos)) {
                                dto.setBusinessObject(forumPostDtos.get(0));
                            }

                        } else if (dto.getForumMsgType().equals(ForumConstants.ForumHandleType.POST_COMMENT.getType())
                                        || dto.getForumMsgType().equals(ForumConstants.ForumHandleType.COMMENT_COMMENT.getType())
                                        || dto.getForumMsgType().equals(ForumConstants.ForumHandleType.LIKE_COMMENT.getType())
                        ) {
                            Map<String, Object> commentParams = new HashMap<>();
                            commentParams.put(LambdaUtil.getFieldName(ForumCommentDto::getId), dto.getBusinessId());
                            commentParams.put(LambdaUtil.getFieldName(ForumCommentDto::getDeletedFlag), SystemConstants.NO);
                            List<ForumCommentDto> forumCommentDtos = forumCommentService.queryList(commentParams);
                            if (CollectionUtils.isNotEmpty(forumCommentDtos)) {
                                dto.setBusinessObject(forumCommentDtos.get(0));
                            }
                        }
                    }


                    return dto;
                }).collect(Collectors.toList());
    }


    @Override
    public void updateById(ForumMsgDto dto) {
        MongodbUtils.update(
                new Query(
                        Criteria.where(SystemConstants.MONGO_ENTITY_ID_FLAG).is(dto.getId())
                ),
                new Update()
                        .set(LambdaUtil.getFieldName(ForumMsgModel::getReadStatus), dto.getReadStatus())
                ,
                MongoCollectionConstants.FORUM_MSG

        );
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return (int) MongodbUtils.count(new Query(sqlWhere(params)), MongoCollectionConstants.FORUM_MSG);
    }

    @Override
    public Long save(ForumMsgDto dto) {
        ForumMsgModel entity = CopyUtils.copyObj(dto, ForumMsgModel.class);
        entity.setId(Snowflake.nextId());
        MongodbUtils.insert(entity, MongoCollectionConstants.FORUM_MSG);
        return entity.getId();
    }


    @Override
    public void deleteById(Long id) {
        MongodbUtils.delete(id, MongoCollectionConstants.FORUM_MSG);
    }

    @Override
    public void deleteBatch(Long[] ids) {
        for (Long id : ids) {
            MongodbUtils.delete(id, MongoCollectionConstants.FORUM_MSG);
        }
    }

}
